home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 220 / 220.xpi / chrome / flashgot.jar / content / flashgot / DMS.js < prev    next >
Encoding:
Text File  |  2010-01-24  |  76.9 KB  |  2,376 lines

  1. /***** BEGIN LICENSE BLOCK *****
  2.  
  3.     FlashGot - a Firefox extension for external download managers integration
  4.     Copyright (C) 2004-2009 Giorgio Maone - g.maone@informaction.com
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.                              
  20. ***** END LICENSE BLOCK *****/
  21.  
  22. const ASK_NEVER = [false, false, false];
  23.  
  24. // *** Base/Windows DMS ********************************************************
  25. function FlashGotDM(name) {
  26.   if (arguments.length > 0) {
  27.     this._init(name);
  28.   }
  29. }
  30.  
  31. FlashGotDM.init = function() {
  32.   FlashGotDM.dms = [];
  33.   FlashGotDM.dmtests = {};
  34.   FlashGotDM.executables = {};
  35.   FlashGotDM.deleteOnExit = [];
  36.   FlashGotDM.deleteOnUninstall = [];
  37.   FlashGotDM.initDMS();
  38. };
  39.  
  40. FlashGotDM.cleanup = function(uninstalling) {
  41.   var trash = [].concat(FlashGotDM.deleteOnExit);
  42.   if (uninstalling) trash = trash.concat(FlashGotDM.deleteOnUninstall);
  43.   for each (var f in trash) {
  44.     if (f instanceof CI.nsIFile) {
  45.       try { f.remove(true); } catch(ex) {}
  46.     }
  47.   }
  48. };
  49.  
  50. FlashGotDM.prototype = {
  51.   _init: function(name) {
  52.     this.name = name;
  53.     const dms = FlashGotDM.dms;
  54.     var pos = dms.length;
  55.     if (name in dms) {
  56.       var other = dms[name];
  57.       for (var j = pos; j-- > 0;) {
  58.         if (dms[j] == other) {
  59.           pos = j;
  60.           break;
  61.         }
  62.       }
  63.     }
  64.     dms[name] = dms[pos] = this;
  65.   }
  66. ,
  67.  
  68.   _cookieManager: null,
  69.   _exeFile: false,
  70.   _supported: null,
  71.   custom: false,
  72.   disabledLink: false,
  73.   disabledSel: false,
  74.   disabledAll: false,
  75.   exeName: "FlashGot.exe",
  76.   askPath: ASK_NEVER,
  77.   cookieSupport: true,
  78.   postSupport: false,
  79.   priority: "",
  80.   autoselect: true,
  81.  
  82.   _codeName: null,
  83.   get codeName() {
  84.     return this._codeName || (this._codeName = this.name.replace(/\W/g,"_"));
  85.   },
  86.   
  87.   getPref: function(name, def) {
  88.     return fg.getPref("dmsopts." + this.codeName + "." + name, def);
  89.   },
  90.   setPref: function(name, value) {
  91.     fg.setPref("dmsopts." + this.codeName + "." + name, value);
  92.   },
  93.   
  94.   get asciiFilter() {
  95.     return this.getPref("asciiFilter", false);
  96.   },
  97.   
  98.   get shownInContextMenu() {
  99.     return this.getPref("shownInContextMenu", false);
  100.   },
  101.   set shownInContextMenu(b) {
  102.     this.setPref("shownInContextMenu", b);
  103.     return b;
  104.   }
  105. ,
  106.   get service() {
  107.     return fg;
  108.   }
  109. ,
  110.   get cookieManager() {
  111.     return this._cookieManager ? this._cookieManager : this._cookieManager =
  112.       CC["@mozilla.org/cookiemanager;1"].getService(CI.nsICookieManager);
  113.   }
  114. ,
  115.   get exeFile() {
  116.     if (typeof(this._exeFile) == "object") return this._exeFile;
  117.     const exeName = this.exeName;
  118.     if (!exeName) return this._exeFile = null;
  119.     if (typeof(FlashGotDM.executables[exeName]) == "object") {
  120.       return this._exeFile = FlashGotDM.executables[exeName];
  121.     }
  122.     try {
  123.       var exeFile = fg.profDir.clone();
  124.       exeFile.append(exeName);
  125.       this._exeFile = this.checkExePlatform(exeFile);
  126.       if(this._exeFile) {
  127.         FlashGotDM.deleteOnUninstall.push(this._exeFile);
  128.         if (this.createExecutable()) {
  129.           this.log(this._exeFile.path + " created");
  130.         }
  131.       }
  132.     } catch(ex) {
  133.       this._exeFile = null;
  134.       this.log("Can't init " + exeName + ":\n" + ex.message);
  135.     }
  136.     return FlashGotDM.executables[exeName] = this._exeFile;
  137.   }
  138. ,
  139.   checkExePlatform: function(exeFile) {
  140.     var path = exeFile.path;
  141.     if (/\/.*\.exe/.test(path)) {
  142.       if (!(fg.getPref("useWine", true) || this.name == fg.defaultDM))
  143.         return null;
  144.       
  145.       if(!FlashGotDM.wine) {
  146.         // check for wine
  147.         var wine = CC["@mozilla.org/file/local;1"].createInstance(CI.nsILocalFile);
  148.         var winePaths = fg.getPref("wine.paths", "/usr/bin/wine:/usr/local/bin/wine:/opt/local/bin/wine:/Applications/Darwine/Wine.bundle/Contents/bin/wine");
  149.         if (!winePaths) return null;
  150.         
  151.         for each(var winePath in winePaths.split(/[;:,]+/)) {
  152.           try {
  153.             wine.initWithPath(winePath);
  154.             if(wine.exists()) {
  155.               FlashGotDM.wine = wine;
  156.               break;
  157.             }
  158.           } catch(e) {}
  159.         }
  160.         if(!FlashGotDM.wine) return null;
  161.         FlashGotDM.wineExecutables = [];
  162.       }
  163.       FlashGotDM.wineExecutables.push(exeFile);
  164.       return exeFile;
  165.     }
  166.     if (FlashGotDMMac.isMac) return null;
  167.     return /\\.*\.sh$/i.test(path) ? null : exeFile;
  168.   }
  169. ,
  170.   get supported() {
  171.     if (typeof(this._supported) == "boolean") return this._supported;
  172.     if (this.customSupportCheck) {
  173.       return this._supported = this.customSupportCheck();
  174.     }
  175.     return this.baseSupportCheck();
  176.   },
  177.   
  178.   baseSupportCheck: function() {
  179.     if (!this.exeName) return true;
  180.     if (!this.exeFile) return false;
  181.     
  182.     var dmtest;
  183.     if (typeof(FlashGotDM.dmtests[this.exeName]) != "string") {
  184.       const dmtestFile = fg.tmpDir.clone();
  185.       dmtestFile.append(this.exeName + ".test");
  186.       try {
  187.         if (dmtestFile.exists()) {
  188.           try { dmtestFile.remove(false); } catch(rex) {}
  189.         }
  190.         this.launchSupportTest(dmtestFile);
  191.         this.log(dmtest = IO.readFile(dmtestFile)); 
  192.       } catch(ex) {
  193.         this.log(ex.message);
  194.         dmtest = "";
  195.       }
  196.       FlashGotDM.dmtests[this.exeName] = dmtest;
  197.     } else dmtest = FlashGotDM.dmtests[this.exeName];
  198.     return this._supported = dmtest.indexOf(this.name + "|OK") > -1;
  199.   }
  200. ,
  201.   readWinRegString: function(hkroot, hkpath, hk) {
  202.     if (!hk) hk = "";
  203.     var key, ret = null;
  204.     if ("@mozilla.org/windows-registry-key;1" in CC) {  // Firefox 1.5 or newer
  205.       key = CC["@mozilla.org/windows-registry-key;1"].createInstance(CI.nsIWindowsRegKey);
  206.       key.open(key["ROOT_KEY_" + hkroot], hkpath, key.ACCESS_READ);
  207.       ret = key.readStringValue(hk);
  208.       key.close();
  209.     } else {
  210.       hkroot = hkroot.replace(/^([A-Z])*_(A_Z).*$/, "HK$1$2"); // CURRENT_USER -> HKCU
  211.       if ("@mozilla.org/winhooks;1" in CC) {    // SeaMonkey or other older non-toolkit application
  212.         key = CC["@mozilla.org/winhooks;1"].getService(CI.nsIWindowsRegistry);
  213.       } else if ("@mozilla.org/browser/shell-service;1" in CC) {
  214.         key = CC["@mozilla.org/browser/shell-service;1"].getService(CI.nsIWindowsShellService)
  215.           && ("getRegistryEntry" in key);
  216.       }
  217.       if (key) key.getRegistryEntry(key[hkroot], hkpath, hk);
  218.     }
  219.     return ret;
  220.   }
  221. ,
  222.   launchSupportTest: function (testFile) {
  223.     this.runNative(["-o", testFile.path], true);
  224.   },
  225.   
  226.   shouldList: function() {
  227.     return this.supported;
  228.   }
  229. ,
  230.   log: function(msg) {
  231.     fg.log(msg);
  232.   }
  233. ,
  234.   updateProgress: function(links, idx, len) {
  235.     if (!links.progress) return;
  236.     if ((idx % 100) == 0) {
  237.       if (!len) {
  238.         links.progress.update(100);
  239.         return;
  240.       }
  241.     }
  242.     links.progress.update(70 + 29 * idx / len);
  243.   }
  244. ,
  245.   isValidLink: null
  246. ,
  247.   get quiet() {
  248.     return this.getPref("quiet") ||
  249.       fg.getPref(this.codeName + ".quiet", false);
  250.   },
  251.   quietOp: function(opType) {
  252.     return this.getPref("quiet." + opType, false) ||
  253.       fg.getPref(this.codeName + ".quiet." + opType, false);
  254.   }
  255. ,
  256.   createJobHeader: function(links, opType) {
  257.     return links.length + ";" + this.name + ";" +
  258.       (this.quietOp(opType) ? fg.OP_QET : opType)
  259.       + ";" + links.folder + ";\n"
  260.   }
  261. ,
  262.   createJobBody: function(links) {
  263.     var jobLines = [];
  264.     var postData = links.postData || "";
  265.  
  266.     for (var j = 0, len = links.length, l; j < len; j++) {
  267.       jobLines.push((l = links[j]).href,
  268.            l.description,
  269.            this.getCookie(l, links),
  270.            postData);
  271.       this.updateProgress(links, j, len);
  272.     }
  273.     return jobLines.join("\n");
  274.   }
  275. ,
  276.   createJob: function(links, opType, extras) {
  277.     var job = this.createJobHeader(links, opType) 
  278.       + this.getReferrer(links) + "\n"
  279.       + this.createJobBody(links);
  280.       
  281.     if (typeof(links.document) == "object") {
  282.       job += "\n" + links.document.referrer + "\n" + links.document.cookie + "\n";
  283.     } else {
  284.       job += "\n\n\n";
  285.     }
  286.     if(!extras) job += "\n\n";
  287.     else {
  288.       while(extras.length < 3) extras.push('');
  289.       job += extras.join("\n");
  290.     }
  291.     var cph = this.getPref("cookiePersistence", null);
  292.     if(cph != null) job += cph;
  293.     return job;
  294.   }
  295. ,
  296.   download: function(links, opType) {
  297.     try {
  298.       links.folder = links.folder || (links.length > 0 ? this.selectFolder(links, opType) : "");
  299.       this.checkCookieSupport();
  300.       this.performDownload(links, opType);
  301.     } catch(ex) {
  302.       this.log(ex + "\n" + ex.stack);
  303.     } finally {
  304.       this.updateProgress(links, 0); // 100%
  305.     }
  306.   }
  307. ,
  308.   // best override point
  309.   performDownload: function(links, opType) {
  310.     this.performJob(this.createJob(links, opType));
  311.   }
  312. ,
  313.   getReferrer: function(links) {
  314.     if (links.redirProcessedBy) {
  315.       for (p in links.redirProcessedBy) {
  316.         if (fg.getPref("redir.anonymous." + p, false)) return "";
  317.       }
  318.     }
  319.     if (!fg.getPref("autoReferrer", true))
  320.       return fg.getPref("fakeReferrer", "");
  321.     
  322.     var ret = links.referrer || links.document && links.document.URL || links[0] && links[0].href;
  323.     
  324.     return (ret && /^https?:*/.test(ret)) ? ret : ""; 
  325.   }
  326. ,
  327.   checkCookieSupport: function() {
  328.     this.getCookie = this.cookieSupport && !fg.getPref("omitCookies")
  329.     ? this._getCookie
  330.     :function() { return ""; }
  331.     ;
  332.   }
  333. ,
  334.   getCookie: function() { return ""; }
  335. ,
  336.   _getCookie: function(link, links) {
  337.     if (!this.cookieSupport) return (this.getCookie = function() { return ""; })();
  338.     var host, cookies;
  339.     if ((cookies = links.cookies)) {
  340.       host = link.host;
  341.       return host && cookies[host] || "";
  342.     }
  343.     this.initCookies(links);
  344.     return this._getCookie(link, links);
  345.   },
  346.   
  347.   initCookies: function(links) {
  348.     var host, cookies, j, objCookie;
  349.     const hostCookies = {};
  350.     
  351.     var l, parts;
  352.     for (j = links.length; j-- > 0;) {
  353.       l = links[j];
  354.       parts = l.href.match(/http[s]{0,1}:\/\/([^\/]+\.[^\/]+)/i); // host?
  355.       if (parts) {
  356.         host = parts[1];
  357.         var hpos = host.indexOf("@");
  358.         if (hpos > -1) host = host.substring(hpos + 1);
  359.         hostCookies[l.host = host] = "";
  360.       } else {
  361.         l.host = null;
  362.       }
  363.     }
  364.     
  365.     var cookieHost, cookieTable, tmpCookie;
  366.     const domainCookies={};
  367.  
  368.     for (var iter = this.cookieManager.enumerator; iter.hasMoreElements();) {
  369.       if ((objCookie = iter.getNext()) instanceof CI.nsICookie) {
  370.         cookieHost = objCookie.host;
  371.         if (cookieHost.charAt(0) == ".") {
  372.           cookieHost = cookieHost.substring(1);
  373.           cookieTable = domainCookies;
  374.           if (typeof(tmpCookie=domainCookies[cookieHost]) != "string") {
  375.             tmpCookie = "";
  376.           }
  377.         } else {
  378.           if (typeof(tmpCookie=hostCookies[cookieHost])!="string") continue;
  379.           cookieTable = hostCookies;
  380.         }
  381.         cookieTable[cookieHost] = tmpCookie.concat(objCookie.name + "=" + objCookie.value + "; ");
  382.       }
  383.     }
  384.  
  385.     for (cookieHost in hostCookies) {
  386.       var dotPos;
  387.       for (host = cookieHost; (dotPos=host.indexOf('.'))>=0; ) { 
  388.         if ((tmpCookie = domainCookies[host])) {
  389.           hostCookies[cookieHost] += tmpCookie;
  390.         }
  391.         host = host.substring(dotPos+1);
  392.       }
  393.     }
  394.     
  395.     links.cookies = hostCookies;
  396.   },
  397.  
  398.   // see http://www.cookiecentral.com/faq/#3.5 and http://www.xulplanet.com/references/xpcomref/ifaces/nsICookie.html
  399.   formatNSCookie: function(cookie) {
  400.     return [
  401.       cookie.host,
  402.       cookie.isDomain ? "TRUE" : "FALSE",
  403.       cookie.path,
  404.       cookie.isSecure? "TRUE" : "FALSE",
  405.       cookie.expires || this.cookieExpires,
  406.       cookie.name,
  407.       cookie.value
  408.     ].join("\t");
  409.   },
  410.   cookieExpires: 0, // to be set once in getCookies()
  411.   createCookieFile: function() {
  412.     if (fg.getPref("omitCookies")) return null;
  413.     
  414.     const cookies = [];
  415.     this.cookieExpires = new Date().getTime() + 24 * 3600 * 3650; // ten years for session cookies
  416.     
  417.     for (var cookie, iter = this.cookieManager.enumerator; iter.hasMoreElements();) {
  418.       if ((cookie = iter.getNext()) instanceof CI.nsICookie) {
  419.         cookies.push(this.formatNSCookie(cookie));
  420.       }
  421.     }
  422.     
  423.     const f = fg.tmpDir.clone();
  424.     f.append("cookies");
  425.     f.createUnique(0, 0600);
  426.     IO.writeFile(f, cookies.join("\n"));
  427.     return f.path;
  428.   }
  429. ,
  430.   createJobFile: function(job) {
  431.     const jobFile = fg.tmpDir.clone();
  432.     jobFile.append("flashgot.fgt");
  433.     jobFile.createUnique(0, 0700);
  434.     IO.writeFile(jobFile, job);
  435.     return jobFile;
  436.   }
  437.   
  438.   performJob: function(job) {
  439.     const jobFile = this.createJobFile(job);
  440.     this.runNative([jobFile.path], false);
  441.   }
  442. ,
  443.   createExecutable: function() {
  444.     const exeFile = this.exeFile;
  445.     if (!exeFile) return false;
  446.     
  447.     var channel;
  448.     
  449.    
  450.     var bis = CC['@mozilla.org/binaryinputstream;1'].createInstance(CI.nsIBinaryInputStream);
  451.     
  452.     bis.setInputStream((
  453.       channel = IOS.newChannel("chrome://flashgot/content/" + this.exeName, null, null)
  454.     ).open());
  455.  
  456.     const bytesCount = channel.contentLength;
  457.     const templateImage = bis.readBytes(bytesCount);
  458.     bis.close();
  459.  
  460.     if (exeFile.exists()) {
  461.       try {
  462.         bis.setInputStream((
  463.           channel = IOS.newChannelFromURI(IOS.newFileURI(exeFile))
  464.         ).open());
  465.         if (channel.contentLength == bytesCount) {
  466.           try {
  467.             if (bis.readBytes(bytesCount) == templateImage) {
  468.               return false;
  469.             }
  470.           } finally {
  471.             bis.close();
  472.           }
  473.         }
  474.       } catch(ioex) {
  475.         this.log(ioex);
  476.       }
  477.     }
  478.     
  479.     var bos = null;
  480.     try {
  481.       const fos = CC["@mozilla.org/network/file-output-stream;1"].createInstance(CI.nsIFileOutputStream);
  482.       fos.init(exeFile, 0x02 | 0x08, 0700, 0);
  483.       bos = CC['@mozilla.org/binaryoutputstream;1'].createInstance(CI.nsIBinaryOutputStream);
  484.       bos.setOutputStream(fos);
  485.       bos.writeBytes(templateImage, bytesCount);
  486.       bos.close();
  487.       return true;
  488.     } catch(ioex) {
  489.       this.log("Error writing " + exeFile.path + ": " + ioex);
  490.     } finally {
  491.       if (bos) try { bos.close(); } catch(e) {}
  492.     }
  493.     return false;
  494.   }
  495. ,
  496.   runNative: function(args, blocking, exeFile) {
  497.     try {
  498.       if (typeof(exeFile) == "object"
  499.         || (exeFile = this.exeFile).exists()
  500.         || this.createExecutable()) {
  501.         const proc = CC['@mozilla.org/process/util;1'].createInstance(
  502.           CI.nsIProcess);
  503.         if (FlashGotDM.wine && FlashGotDM.wineExecutables.indexOf(exeFile) > -1) {
  504.           args.unshift(exeFile.path);
  505.           exeFile = FlashGotDM.wine;
  506.         }
  507.         proc.init(exeFile);
  508.         this.log("Running " + exeFile.path + " " + args.join(" ") + " -- " +(blocking ? "blocking" : "async") );
  509.         proc.run(blocking, args, args.length, {});
  510.         if (blocking && proc.exitValue != 0) {
  511.           this.log("Warning: native invocation of\n"
  512.             + exeFile.path
  513.             + "\nwith arguments <"
  514.             + args.join(" ")
  515.             + ">\nreturned " + proc.exitValue);
  516.         }
  517.         return proc.exitValue;
  518.       } else {
  519.         this.log("Bad executable " + exeFile);
  520.       }
  521.     } catch(err) {
  522.       this.log("Error running native executable:\n" + exeFile.path + 
  523.         " " + args.join(" ") + "\n" + err.message);
  524.     }
  525.     return 0xffffffff;
  526.   }
  527. ,
  528.   getWindow: function() {
  529.     return fg.getWindow();
  530.   }
  531. ,
  532.   selectFolder: function(links, opType) { 
  533.     if (this.quiet || this.quietOp(opType)) return "";
  534.  
  535.     const autoPref_FF = "browser.download.useDownloadDir";
  536.     const autoPref_Moz = "browser.download.autoDownload";
  537.     
  538.     var initialDir = null;
  539.     var downloadDir = null;
  540.     links.quickDownload = false;
  541.     
  542.     const pref = CC["@mozilla.org/preferences-service;1"].getService(CI.nsIPrefBranch);
  543.     
  544.     function findDownloadDir(prefName) {
  545.       try {
  546.         downloadDir = initialDir = pref.getComplexValue(prefName, CI.nsILocalFile);
  547.         return prefName;
  548.       } catch(ex) {
  549.         return "";
  550.       }
  551.     }
  552.     const isMulti = opType != fg.OP_ONE;
  553.     const multiDirPref = "flashgot.multiDir";
  554.     var downloadDirPref = 
  555.                     (isMulti && findDownloadDir(multiDirPref)) ||
  556.                     findDownloadDir("browser.download.dir") ||
  557.                     findDownloadDir("browser.download.downloadDir") || 
  558.                     findDownloadDir("browser.download.defaultFolder") ||
  559.                     "browser.download.dir"; 
  560.     
  561.     if (isMulti) downloadDirPref = multiDirPref;
  562.     
  563.     try {
  564.       links.quickDownload = pref.getBoolPref(autoPref_FF);
  565.     } catch(noFFEx) {
  566.       try {
  567.         links.quickDownload = pref.getBoolPref(autoPref_Moz);
  568.       } catch(noMozEx) {}
  569.     }
  570.    
  571.     if (!this.askPath[opType]) return "";
  572.     
  573.     if (((!isMulti) || fg.getPref("multiQuiet", false)) && 
  574.         downloadDir && downloadDir.exists() && downloadDir.isDirectory()  && 
  575.         links.quickDownload) {
  576.       return downloadDir.path;
  577.     }
  578.     
  579.     var params = {
  580.       title: "FlashGot (" + this.name.replace(/[\(\)]/g, "") + ")",
  581.       initialDir: initialDir,
  582.       choosenDir: null
  583.     }
  584.     
  585.     this.getWindow().openDialog(
  586.               "chrome://flashgot/content/chooser.xul",
  587.               "flashgotChooser",
  588.               "chrome, dialog, modal, dependent, centerscreen",
  589.               params);
  590.     
  591.     if (params.choosenDir) {
  592.       pref.setComplexValue(downloadDirPref, CI.nsILocalFile, params.choosenDir);
  593.       var path = new String(params.choosenDir.path);
  594.       path._fgSelected = true;
  595.       return path;
  596.     }
  597.   
  598.     throw new Error("Download cancelled by user");
  599.  
  600.   },
  601.   sanitizeWinArg: function(a) {
  602.     return a.replace(/([\|\(\) &\^])/g, "^$1"); 
  603.   },
  604.   supportURLList: function(links, argsTemplate) {
  605.     if (/\[[^\]]*UFILE[^\]]*\]/.test(argsTemplate) && links.length) {
  606.       // we must create a file list
  607.       var sep = fg.isWindows ? "\r\n" : "\n";
  608.       var urlList = "";
  609.       for (j = 0; j < links.length; j++) {
  610.         urlList += links[j].href + sep;
  611.       }
  612.       links.length = 1;
  613.       return FlashGotDMX.prototype.createJobFile.call(this, urlList).path;
  614.     }
  615.     return null;
  616.   },
  617.   nativeUI: null,
  618.   hideNativeUI: function(document) {
  619.     if (!(this.nativeUI && this.getPref("hideNativeUI", true))) return;
  620.     fg.hideNativeUI(document, this.nativeUI);
  621.   }
  622. }
  623.  
  624.  
  625.  
  626.  
  627. // *** Unix-like DMS ***********************************************************
  628. function FlashGotDMX(name, cmd, argsTemplate) {
  629.   if (arguments.length != 0) {
  630.     this._init(name);
  631.     const cmds = FlashGotDMX.prototype.unixCmds;
  632.     cmds[name] = cmd;
  633.     this.unixCmd = cmd;
  634.     if (argsTemplate) this.argsTemplate = argsTemplate;
  635.     this.cookieSupport =  /\[.*?(?:CFILE|COOKIE).*?\]/.test(this.argsTemplate);
  636.   }
  637.   if (FlashGotDMMac.isMac) {
  638.     this.createJobFile = FlashGotDMMac.prototype.createJobFile;
  639.   }
  640. }
  641. FlashGotDMX.prototype = new FlashGotDM();
  642. FlashGotDMX.constructor = FlashGotDMX;
  643. FlashGotDMX.prototype.exeName = "flashgot.sh";
  644. FlashGotDMX.prototype.terminal = false;
  645. FlashGotDMX.prototype.askPath = [true, true, true];
  646. FlashGotDMX.prototype.unixCmds = {};
  647. FlashGotDMX.prototype.__defineGetter__("unixShell", function() {
  648.   var f = CC["@mozilla.org/file/local;1"].createInstance(CI.nsILocalFile);
  649.   try {
  650.     f.initWithPath("/bin/sh");
  651.     if (!f.exists()) {
  652.       this.log(f.path + " not found");
  653.       f = null;
  654.     }
  655.   } catch(ex) {
  656.     f = null;
  657.     this.log("No *X shell: " + ex.message);
  658.   }
  659.   delete FlashGotDMX.prototype.unixShell;
  660.   return FlashGotDMX.prototype.unixShell = f;
  661. });
  662.  
  663. FlashGotDMX.prototype.argsTemplate = "[URL]";
  664. FlashGotDMX.prototype.launchSupportTest = function(testFile) {
  665.   const cmds = this.unixCmds;
  666.   var script="(\n";
  667.  
  668.   for (var name in cmds) {
  669.     cmd = cmds[name];
  670.     script += " which \"" + cmd + "\" && echo '"
  671.       + name + "|OK' || echo '" + name+"|KO'\n"; 
  672.   }
  673.   script += ") > '" + testFile.path + "' 2>/dev/null\n"; 
  674.   this.performJob(script, true);
  675. };
  676.  
  677. FlashGotDMX.prototype.createCmdLine = function(parms, cmd) {
  678.   return (cmd || this.unixCmd) + " " +
  679.     this.argsTemplate.replace(/\[(.*?)(URL|FNAME|REFERER|COOKIE|FOLDER|POST|UFILE|CFILE)(.*?)\]/g,
  680.       function(all, before, parm, after) {
  681.           v = parms[parm]; 
  682.           return typeof(v) != "undefined" && v != null
  683.             ? before + v + after
  684.             : "";
  685.       }
  686.    ) +" &\n";
  687. };
  688. FlashGotDMX.prototype.shellEsc = function(s) {
  689.   return s ? s.replace(/([\\\*\?\[\]\$&<>\|\(\)\{\};"'`])/g,"\\$1").replace(/\s/g,"\\ ") : null;
  690. };
  691. FlashGotDMX.prototype.createJob = function(links, opType) {
  692.   const shellEsc = this.shellEsc;
  693.   // basic implementation
  694.  
  695.   const folder = shellEsc(links.folder);
  696.   const referrer = shellEsc(this.getReferrer(links));
  697.   const postData = shellEsc(links.postData);
  698.   
  699.   var cmd = this.unixCmd;
  700.   
  701.   var job;
  702.   if (this.terminal) {
  703.     job =  "if [ \"$COLORTERM\" = \"gnome-terminal\" ] && which gnome-terminal 2>/dev/null; then DOWN_CMD='gnome-terminal -x " + cmd
  704.       + "'; elif which xterm 2>/dev/null; then DOWN_CMD='xterm -e " + cmd 
  705.       + "'; else DOWN_CMD='" + cmd + "'; fi\n";
  706.     cmd = "$DOWN_CMD";
  707.   } else {
  708.     job = "";
  709.   }
  710.   
  711.   if (links.folder) job += "cd '" + links.folder + "'\n";
  712.     
  713.   var l, url;
  714.   
  715.   var cookieFile = this.createCookieFile();
  716.   var urlListFile = this.supportURLList(links, this.argsTemplate);
  717.   for (var j = 0, len = links.length; j < len; j++) {
  718.     l = links[j];
  719.     url = l.href;
  720.     job += this.createCmdLine({
  721.       URL: shellEsc(url),
  722.       FNAME: l.fname && shellEsc(l.fname) || null,
  723.       REFERER: referrer, 
  724.       COOKIE: shellEsc(this.getCookie(l, links)),
  725.       CFILE: cookieFile,
  726.       FOLDER: folder, 
  727.       POST: postData,
  728.       UFILE: shellEsc(urlListFile)
  729.     }, cmd);
  730.     this.updateProgress(links, j, len);
  731.   }
  732.   return job;
  733. };
  734. FlashGotDMX.prototype.performJob = function(job, blocking) {
  735.   const jobFile = this.createJobFile("#!" + this.unixShell.path + "\n" + job);
  736.   jobFile.permissions = 0700;
  737.   var exeFile = FlashGotDMMac.isMac ? FlashGotDMMac.exeFile : jobFile;
  738.   this.runNative([], blocking, exeFile);
  739. };
  740. FlashGotDMX.prototype.checkExePlatform = function(exeFile) {
  741.   return this.unixShell && exeFile;
  742. };
  743. FlashGotDMX.prototype.createExecutable = function() {
  744.   return false;
  745. };
  746.  
  747.  
  748.  
  749.  
  750.  
  751.  
  752. // *** Mac OS X DMS ************************************************************
  753. function FlashGotDMMac(name, creatorId, macAppName) {
  754.   if (arguments.length != 0) {
  755.     this._initMac(name, creatorId, macAppName);
  756.   }
  757. }
  758. FlashGotDMMac.exeFile = null;
  759. FlashGotDMMac.appleScriptFile = null;
  760. FlashGotDMMac.appleScriptName = "flashgot-mac-script";
  761. FlashGotDMMac.OSASCRIPT = "/usr/bin/osascript";
  762. FlashGotDMMac.isMac = (function() {
  763.   const f = CC["@mozilla.org/file/local;1"].createInstance(CI.nsILocalFile);
  764.   try {
  765.     f.initWithPath(FlashGotDMMac.OSASCRIPT);
  766.     return f.exists();
  767.   } catch(ex) {
  768.   }
  769.   return false;
  770. })();
  771. FlashGotDMMac.prototype = new FlashGotDM();
  772. FlashGotDMMac.constructor = FlashGotDMMac;
  773. FlashGotDMMac.prototype.exeName = "FlashGot";
  774. FlashGotDMMac.prototype.cookieSupport = false;
  775. FlashGotDMMac.prototype.macCreators = [];
  776. FlashGotDMMac.prototype._initMac = function(name, creatorId, macAppName) {
  777.   this._init(name);
  778.  
  779.   if (creatorId) {
  780.     const creators=FlashGotDMMac.prototype.macCreators;
  781.     creators[creators.length] = {name: name, id: creatorId};
  782.   }
  783.   this.macAppName = macAppName ? macAppName : name;
  784.   this.initAppleScriptBridge();
  785.   FlashGotDMMac.exeFile = this.exeFile;
  786. };
  787.  
  788. FlashGotDMMac.prototype.initAppleScriptBridge = function() {
  789.   if (FlashGotDMMac.appletScriptFile) return;
  790.   
  791.   var home = fg.home && fg.home.parent;
  792.   if (home) home.append("mac-flashgot");
  793.  
  794.   if (!(home && home.exists() && home.isWritable())) {
  795.     (FlashGotDMMac.appleScriptFile = fg.tmpDir.clone())
  796.       .append(FlashGotDMMac.appleScriptName);
  797.     return;
  798.   }
  799.   (FlashGotDMMac.appleScriptFile = home.clone())
  800.     .append(FlashGotDMMac.appleScriptName);
  801.   (FlashGotDMMac.prototype._exeFile = home.clone()).append(this.exeName);
  802.   
  803.   this.log("Setting executable permissions on " + this._exeFile.path);
  804.   this._exeFile.permissions = 0700;
  805.   FlashGotDMMac.prototype.createExecutable = function() { return false; }
  806. }
  807. FlashGotDMMac.prototype.shellEsc = function(s) {
  808.   return s ? "'" + s.replace(/'/g, '"\'"') + "'" : null; 
  809. }
  810. FlashGotDMMac.prototype.createScriptLauncher = function() {
  811.   return "#!/bin/sh\n" +
  812.     "SCRIPT=" + this.shellEsc(FlashGotDMMac.appleScriptFile.path) + "\n" +
  813.     "USCRIPT=\"$SCRIPT.$$\"\n" + 
  814.     "mv \"$SCRIPT\" \"$USCRIPT\" || exit 1\n" +
  815.     "head -n 1 \"$USCRIPT\" | grep '#!' >/dev/null &&  \"$USCRIPT\" || " +
  816.     FlashGotDMMac.OSASCRIPT + " \"$USCRIPT\"";
  817. };
  818. FlashGotDMMac.prototype.checkExePlatform = function(exeFile) {
  819.   return FlashGotDMMac.isMac && exeFile || null;
  820. };
  821. FlashGotDMMac.prototype.createExecutable = function() {
  822.   
  823.   
  824.   var exeFile = this._exeFile;
  825.   if (!exeFile) return false;
  826.  
  827.   try {
  828.    var scriptLauncher = this.createScriptLauncher();
  829.    var mustCreate = true;
  830.    if (exeFile.exists()) {
  831.      if (IO.readFile(exeFile) == scriptLauncher) {
  832.        exists = true;
  833.        if (exeFile.isExecutable()) return false;
  834.        mustCreate = false;
  835.      } else {
  836.        this.log(exeFile.path + " is corrupted or obsolete, replacing it...");
  837.        try { exeFile.remove(true); } catch(rex) {} 
  838.      }
  839.    } else {
  840.      this.log(exeFile.path + " not found, creating it...");
  841.    }
  842.    if (mustCreate) {
  843.       this.log("Creating Mac executable");
  844.       exeFile.create(0, 0700);
  845.       IO.writeFile(exeFile, scriptLauncher);
  846.      
  847.       try {
  848.         this.log("Trying to reset Leopard's quarantine attribute...");
  849.         var xattr =  CC["@mozilla.org/file/local;1"].createInstance(CI.nsILocalFile);
  850.         xattr.initWithPath("/usr/bin/xattr");
  851.         this.runNative(["-d", "com.apple.quarantine", exeFile.path], true, xattr);
  852.       } catch(e) {
  853.         this.log("Couldn't clear quarantine attribute " + e); 
  854.       }
  855.    }
  856.    this.log("Setting executable permissions on " + exeFile.path);
  857.    exeFile.permissions = 0700;
  858.    
  859.   
  860.    
  861.    
  862.    return mustCreate;
  863.   } catch(ex) {
  864.     this.log("Cannot create Mac executable: " + ex.message);
  865.   }
  866.   return false;
  867. };
  868. FlashGotDMMac.prototype.launchSupportTest = function(testFile) {
  869.   const creators = FlashGotDMMac.prototype.macCreators;
  870.   
  871.   var s = [
  872.     'global gRes',
  873.     'set gRes to ""',
  874.     'on theTest(theName, theId)',
  875.     '  set gRes to gRes & theName',
  876.     '  try',
  877.     '    tell app "Finder" to get application file id theId',
  878.     '    set gRes to gRes & "|OK\n"',
  879.     '  on error',
  880.     '    set gRes to gRes & "|KO\n"',
  881.     '  end try',
  882.     'end theTest'
  883.   ];
  884.   for (var j = creators.length; j-- > 0; ) {
  885.     s.push('theTest("' + creators[j].name + '","' +creators[j].id + '")'); 
  886.   }
  887.   s.push(
  888.     'set theFile to POSIX file "' + testFile.path + '"',
  889.     'try',
  890.     '  set fh to open for access theFile with write permission',
  891.     '  write (gRes) to theFile',
  892.     '  close access fh',
  893.     'on error',
  894.     '  try',
  895.     '    close access fh',
  896.     '  end try',
  897.     'end try'
  898.   );
  899.   this.performJob(s.join("\n"), true);
  900. };
  901. FlashGotDMMac.prototype.createJobFile = function(job) {
  902.   const jobFile = FlashGotDMMac.appleScriptFile;
  903.   try {
  904.     jobFile.remove(true);
  905.   } catch(ex) {}
  906.   try {
  907.     jobFile.create(0, 0600);
  908.     IO.writeFile(jobFile, job, /^#/.test(job) ? null : fg.getPref("appleScriptEncoding"));
  909.     return jobFile;
  910.   } catch(ex) {
  911.     this.log("Cannot write " + (jobFile && jobFile.path) + ex.message);
  912.   }
  913.   return null;
  914. }
  915. FlashGotDMMac.prototype.performJob = function(job, blocking) {
  916.   if (this.createJobFile(job)) 
  917.     this.runNative([], blocking, this.exeFile);
  918. };
  919.  
  920. FlashGotDMMac.prototype.createJob = function(links,opType) {
  921.   const referrer = this.getReferrer(links);
  922.   var job = "tell application \""+ this.macAppName+ "\"\n";
  923.   for (var j = 0, len = links.length; j < len; j++) {
  924.     job += 'GetURL "' + links[j].href + '" from "' + referrer  + "\"\n";
  925.     this.updateProgress(links, j, len);
  926.   }
  927.   job += "end tell\n";
  928.   return job;
  929. };
  930.  
  931.  
  932.  
  933. // *** Custom DMS **************************************************************
  934. function FlashGotDMCust(name) {
  935.   if (arguments.length == 0 || (!name) || (!name.length)) return;
  936.   name = name.replace(/,/g, " ");
  937.   this._init(name);
  938.   this.prefsBase = "custom." + this.codeName + ".";
  939. }
  940.  
  941. FlashGotDMCust.init = function() {
  942.   const names = fg.getPref("custom", "").split(/\s*,\s*/);
  943.   for (var j = names.length; j-->0;) {
  944.     new FlashGotDMCust(names[j]);
  945.   }
  946. }
  947.  
  948. FlashGotDMCust.persist = function() {
  949.   const dms = FlashGotDM.dms;
  950.   const cdms = [];
  951.   for (var j = dms.length; j-->0;) {
  952.     if (dms[j].custom) cdms.push(dms[j].name);
  953.   }
  954.   fg.setPref("custom", cdms.join(","));
  955. }
  956.  
  957. FlashGotDMCust.prototype = new FlashGotDM();
  958. FlashGotDMCust.constructor = FlashGotDM;
  959.  
  960. delete FlashGotDMCust.prototype.launchSupportTest;
  961. delete FlashGotDMCust.prototype.exeFile;
  962. FlashGotDMCust.prototype.PLACEHOLDERS = ["URL", "COMMENT", "REFERER", "COOKIE", "FOLDER", "POST", "UFILE", "CFILE"];
  963.  
  964. FlashGotDMCust.prototype.custom = true;
  965. FlashGotDMCust.prototype. _supported = true;
  966. FlashGotDMCust.prototype.cookieSupport = false;
  967. FlashGotDMCust.prototype.postSupport = true;
  968. FlashGotDMCust.prototype.askPath = [true, true, true];
  969.  
  970. FlashGotDMCust.prototype.__defineGetter__("exeFile",function() {
  971.   try {
  972.     return fg.prefs.getComplexValue(this.prefsBase + "exe", 
  973.       CI.nsILocalFile);
  974.   } catch(ex) {
  975.     return null;
  976.   }
  977. });
  978. FlashGotDMCust.prototype.__defineSetter__("exeFile",function(v) {
  979.   try {
  980.     if (v) {
  981.       fg.prefs.setComplexValue(this.prefsBase + "exe", 
  982.           CI.nsILocalFile,v);
  983.       return v;
  984.     }
  985.   } catch(ex) {
  986.   }
  987.   return null;
  988. });
  989.  
  990. FlashGotDMCust.prototype.__defineGetter__("argsTemplate", function() {
  991.   if (this.forcedTemplate) return this.forcedTemplate;
  992.   var t = fg.getPref(this.prefsBase+"args", "[URL]");
  993.   return /['"`]/.test(t) ? this.argsTemplate = t : t;
  994. });
  995. FlashGotDMCust.prototype.__defineSetter__("argsTemplate",function(v) {
  996.   if (!v) {
  997.     v = "";
  998.   } else {
  999.     v = v.replace(/['"`]/g,"");
  1000.   }
  1001.   fg.setPref(this.prefsBase + "args", v);
  1002.   this.askPath = [];
  1003.   return v;
  1004. });
  1005.  
  1006.  
  1007. FlashGotDMCust.prototype.download = function(links, opType) {
  1008.   const t = this.argsTemplate;
  1009.   this.cookieSupport = /\[.*?(?:CFILE|COOKIE).*?\]/.test(t);
  1010.   this.askPath[opType] = /\[.*?FOLDER.*?\]/.test(t);
  1011.   var exeFile = this.exeFile;
  1012.   // portable hacks
  1013.   if (exeFile && !exeFile.exists()) {
  1014.     // try changing the first part of path
  1015.     var path = exeFile.path;
  1016.     var profPath = fg.profDir.path;
  1017.     var pos1, pos2;
  1018.     if (path[1] == ":" && profPath[1] == ":") { 
  1019.       // easy, it's Windows, swap drive letter
  1020.       path = profPath[0] + path.substring(1);
  1021.     } else if(path.indexOf("/mount/") == 0 && profPath.indexOf("/mount/") == 0) {
  1022.       pos1 = path.indexOf("/", 7);
  1023.       pos2 = profPath.indexOf("/", 7);
  1024.       path = "/mount/" + profPath.substring(7, pos2) + path.substring(pos1); 
  1025.     } else if((pos1 = path.indexOf("/",1)) > 0 && (pos2 = profPath.indexOf("/", 1)) > 0) {
  1026.       path = profPath.substring(0, pos2) + path.substring(pos1);
  1027.     } else exeFile = null;
  1028.     if (exeFile) {
  1029.       exeFile = exeFile.clone().QueryInterface(CI.nsILocalFile).initWithPath(path);
  1030.       if (!exeFile.exists()) exeFile = null;
  1031.     }
  1032.   }
  1033.   links.exeFile= (exeFile || 
  1034.     (exeFile = this.exeFile = this.locateExeFile())) ? exeFile : null;
  1035.   FlashGotDM.prototype.download.call(this, links, opType);
  1036. };
  1037.  
  1038. FlashGotDMCust.prototype.locateExeFile = function(name) {
  1039.  
  1040.  
  1041.   if (!name) name = this.name;
  1042.   var title = fg.getString("custom.exeFile");
  1043.   title = 'FlashGot (' + name + ') - ' + title;
  1044.   
  1045.   const fp = CC["@mozilla.org/filepicker;1"].createInstance(CI.nsIFilePicker);
  1046.   const win = this.getWindow();
  1047.   fp.init(win, title, CI.nsIFilePicker.modeOpen);
  1048.   fp.appendFilters(CI.nsIFilePicker.filterApps);
  1049.   fp.appendFilters(CI.nsIFilePicker.filterAll);
  1050.  
  1051.   if (fp.show() == CI.nsIFilePicker.returnOK) {
  1052.     var file = fp.file.QueryInterface(CI.nsILocalFile);
  1053.     if (file.exists()) {
  1054.       return file;
  1055.     }
  1056.   }
  1057.   return null;
  1058. };
  1059.  
  1060. FlashGotDMCust.prototype._addParts=function(a, s) {
  1061.   var parts=s.split(/\s+/);
  1062.   var k, p;
  1063.   for (k in parts) {
  1064.     if ((p = parts[k])) {
  1065.       a[a.length] = p;
  1066.     }
  1067.   }
  1068. };
  1069.  
  1070. FlashGotDMCust.prototype.makeArgs = function(parms) {
  1071.   const args = [];
  1072.   var t = this.argsTemplate;
  1073.   var j, v, len, s;
  1074.   
  1075.   var idx;
  1076.   
  1077.   for (var m; 
  1078.       m = t.match( /\[([\s\S]*?)(\S*)\b(URL|COMMENT|FNAME|REFERER|COOKIE|FOLDER|POST|CFILE|UFILE)\b(\S*?)([\s\S]*?)\]/); 
  1079.       t = t.substring(idx + m[0].length) 
  1080.      ) {
  1081.  
  1082.     if ((idx = m.index) > 0) {
  1083.       this._addParts(args, t.substring(0, idx));
  1084.     }
  1085.     
  1086.     v = parms[m[3]];
  1087.     if (!v) continue;
  1088.     
  1089.     this._addParts(args, m[1]);
  1090.     args[args.length] = m[2] + v + m[4];
  1091.     this._addParts(args, m[5]);
  1092.   }
  1093.   
  1094.   if (t.length) {
  1095.     this._addParts(args, t);
  1096.   }
  1097.   return args;
  1098. };
  1099.  
  1100. FlashGotDMCust.prototype.createJob = function(links, opType) {
  1101.   return { links: links, opType: opType };
  1102. };
  1103.  
  1104. FlashGotDMCust.prototype.shellEsc = function(s) {
  1105.   return s ? '"' + s.replace(/"/g, '""') + '"' : null;
  1106. }
  1107.  
  1108. FlashGotDMCust.prototype.winEscHack = function(s) {
  1109.   // hack for bug at http://mxr.mozilla.org/seamonkey/source/xpcom/threads/nsProcessCommon.cpp#149 
  1110.   return (/[;&=]/.test(s) && !/\s/.test(s)) // "=" and ";" are command line separators on win!!!
  1111.     ? s + " " : s; // we add a space to force escaping
  1112. }
  1113.  
  1114. FlashGotDMCust.prototype.performJob = function(job) {
  1115.   const links = job.links;
  1116.   const exeFile = links.exeFile;
  1117.   if (links.length < 1 || !exeFile) return;
  1118.   
  1119.   var esc = (fg.isWindows && this.getPref("winEscHack", true))
  1120.     ? this.winEscHack : function(s) { return s; }
  1121.   
  1122.   const folder = links.folder;
  1123.   const referrer = esc(this.getReferrer(links));
  1124.   const postData = esc(links.postData);
  1125.   var cookieFile = this.createCookieFile();
  1126.   var urlListFile = this.supportURLList(links, this.argsTemplate);
  1127.   var maxLinks = fg.getPref(this.prefsBase + "maxLinks", 0);
  1128.   if (maxLinks > 0 && links.length > maxLinks) {
  1129.     this.log("Too many links (" + links.length + "), cutting to " 
  1130.         + this.prefsBase + "maxLinks (" + maxLinks + ")");
  1131.     links.length = maxLinks;
  1132.   }
  1133.   var l;
  1134.  
  1135.   
  1136.   for (var j = 0, len = links.length; j < len; j++) {
  1137.     l = links[j];
  1138.     this.runNative(
  1139.       this.makeArgs({
  1140.         URL: esc(l.href),
  1141.         COMMENT: esc(l.description),
  1142.         FNAME: l.fname && esc(l.fname) || null,
  1143.         REFERER: referrer, 
  1144.         COOKIE: esc(this.getCookie(l, links)), 
  1145.         FOLDER: folder, 
  1146.         POST: postData,
  1147.         CFILE: cookieFile,
  1148.         UFILE: urlListFile
  1149.        }),
  1150.        false, exeFile);
  1151.     this.updateProgress(links, j, len);
  1152.   }
  1153. };
  1154. FlashGotDMCust.prototype.checkExePlatform = function(exeFile) {
  1155.   return exeFile;
  1156. };
  1157. FlashGotDMCust.prototype.createExecutable = function() {
  1158.   return false;
  1159. };
  1160. // End FlashGotDMCust.prototype
  1161.  
  1162. // *****************************************************************************
  1163. // END DMS CLASSES
  1164. // *****************************************************************************
  1165.  
  1166. // DMS initialization
  1167.  
  1168. FlashGotDM.initDMS = function() {
  1169.   const isWin = fg.isWindows;
  1170.   var dm;
  1171.  
  1172.   new FlashGotDM("BitComet");
  1173.  
  1174.   dm = new FlashGotDM("Download Accelerator Plus");
  1175.   dm.nativeUI = "#dapctxmenu1, #dapctxmenu2";
  1176.   
  1177.   dm.performDownload =  function(links, opType) {
  1178.     if (!("IDAPComponent" in CI)) {
  1179.       this.log("DAP extension not found, falling back to IE integration");
  1180.       FlashGotDM.prototype.performDownload.apply(this, arguments);
  1181.       return;
  1182.     }
  1183.     
  1184.     function getDAP() {
  1185.       return CC["@speedbit.com/dapfirefox/dapcomponent;1"].createInstance(CI.IDAPComponent);
  1186.     }
  1187.     function downloadDoc(doc) {
  1188.       getDAP().RigthClickMenuDownloadAll(doc, "Firefox");
  1189.       doc.defaultView.location.href = "about:blank";
  1190.     }
  1191.     
  1192.     try {
  1193.     
  1194.       if (opType == fg.OP_ONE) {
  1195.         var l = links[0];
  1196.         getDAP().RigthClickMenuDownload(
  1197.           l.href, this.getReferrer(links), this.getCookie(l, links), l.description, "Firefox");
  1198.         return;
  1199.       }
  1200.       
  1201.       if (!links.document) {
  1202.         this.log("DAP: No document found");
  1203.         return;
  1204.       }
  1205.       
  1206.       var doc = links.document;
  1207.       var url = doc.URL;
  1208.       if (opType == fg.OP_SEL) {
  1209.         var bwin = links.browserWindow || fg.getBrowserWindow(doc);
  1210.         if (!bwin) {
  1211.           this.log("DAP: no browser window found");
  1212.           return;
  1213.         }
  1214.         var f = bwin.document.getElementById("_flashgot_iframe");
  1215.         
  1216.         f.docShell.QueryInterface(CI.nsIWebPageDescriptor).loadPage(
  1217.           DOM.getDocShellFromWindow(doc.defaultView).QueryInterface(CI.nsIWebPageDescriptor).currentDescriptor,
  1218.           2
  1219.         );
  1220.         
  1221.         var dm = this;
  1222.         f.addEventListener("DOMContentLoaded", function(ev) {
  1223.           try {
  1224.             var f = ev.currentTarget;
  1225.             f.removeEventListener(ev.type, arguments.callee, false);
  1226.             var doc = f.contentDocument;
  1227.             if (doc.URL != url) return;
  1228.             var root = doc.documentElement;
  1229.             while(root.firstChild) root.removeChild(root.firstChild);
  1230.             root.appendChild(doc.createElement("head"));
  1231.             root.appendChild(doc.createElement("body"));
  1232.             var frag = doc.createDocumentFragment();
  1233.             var a, l;
  1234.             for(var j = 0; j < links.length; j++) {
  1235.               a = doc.createElement("a");
  1236.               l = links[j];
  1237.               a.href = l.href;
  1238.               a.appendChild(doc.createTextNode(l.description));
  1239.               frag.appendChild(a);
  1240.             }
  1241.             doc.body.appendChild(frag);
  1242.             downloadDoc(doc, "Firefox");
  1243.           } catch(e) {
  1244.             dm.log("DAP Selection: " + e.message + " - " + e.stack);
  1245.           }
  1246.         }, false);
  1247.         
  1248.       } else {
  1249.         downloadDoc(doc);
  1250.       }
  1251.     } catch(e) {
  1252.       this.log("DAP: " + e.message + " - " + e.stack);
  1253.       return;
  1254.     }
  1255.   };
  1256.   
  1257.   
  1258.   
  1259.   
  1260.   new FlashGotDM("Download Master");
  1261.   
  1262.   for each (dm in [new FlashGotDM("DTA"), new FlashGotDM("DTA (Turbo)")]) {
  1263.     dm.__defineGetter__("supported", 
  1264.       function() { 
  1265.         return  "dtaIFilterManager" in CI || "@downthemall.net/privacycontrol;1" in CC 
  1266.     });
  1267.     dm.turboDTA = /Turbo/.test(dm.name);
  1268.     dm.nativeUI = dm.turboDTA
  1269.       ? "#context-dta-savelinkt, #context-tdta, #dtaCtxTDTA, #dtaCtxSaveT, #dtaCtxTDTA-direct, #dtaCtxSaveT-direct"
  1270.       : "#context-dta-savelink, #context-dta, #dtaCtxDTA, #dtaCtxSave, #dtaCtxDTA-direct, #dtaCtxSave-direct";
  1271.       
  1272.     dm.performDownload = function(links, opType) {
  1273.       if(!links.document) {
  1274.         this.log("No document found in " + links);
  1275.         return;
  1276.       }
  1277.       var w = links.browserWindow || fg.getBrowserWindow(links.document);
  1278.       if(!(w && w.DTA_AddingFunctions && w.DTA_AddingFunctions.saveLinkArray)) {
  1279.         this.log("DTA Support problem: " + w + ", " + (w && w.DTA_AddingFunctions) + ", tb:" +
  1280.           w.gBrowser + ", wl:" + w.location + ", wo:" + w.wrappedJSObject + ", " +
  1281.             (w && w.DTA_AddingFunctions && w.DTA_AddingFunctions.saveLinkArray));
  1282.         return;
  1283.       }
  1284.       var mlSupport = w.DTA_getLinkPrintMetalink;
  1285.       var turbo = this.turboDTA;
  1286.       var cs = links.document && links.document.characterSet || "UTF-8";
  1287.       var anchors = [], images = [], l, arr;
  1288.       var hash, ml;
  1289.       var referrer = this.getReferrer(links);
  1290.       var tag;
  1291.       var single = opType == fg.OP_ONE;
  1292.  
  1293.       var wrapURL = w.DTA_URL
  1294.         ? w.DTA_URL.toSource().indexOf("DTA_URL(url, preference)") > -1
  1295.           ? function(url, cs) { return new w.DTA_URL(IOS.newURI(url, cs, null)); }
  1296.           : function(url, cs) { return new w.DTA_URL(url, cs); }
  1297.         : function(url) { return url };
  1298.       var lastItem = null;
  1299.       for (var j = 0, len = links.length; j < len; j++) {
  1300.         l = links[j];
  1301.         arr = single || !(tag = l.tagName) || tag.toLowerCase() == "a" ? anchors : images;
  1302.         try {
  1303.           arr.push(lastItem = { 
  1304.               url: wrapURL(l.href, cs),
  1305.               description: l.description,
  1306.               ultDescription: '',
  1307.               referrer: referrer
  1308.           });
  1309.           
  1310.           if (arr == anchors && mlSupport && l.href.indexOf("#") > 0) {
  1311.             hash = l.href.match(/.*#(.*)/)[1];
  1312.             ml = mlSupport(l.href);
  1313.             if (ml) {
  1314.               arr.push(lastItem = {
  1315.                 url: wrapURL(ml, cs),
  1316.                 description: '[metalink] http://www.metalinker.org/',
  1317.                 ultDescription: '',
  1318.                 referrer: referrer,
  1319.                 metalink: true
  1320.               });
  1321.             }
  1322.           } 
  1323.         } catch(e) {
  1324.           this.log("DTA: " + e.message);
  1325.         }
  1326.         this.updateProgress(links, j, len);
  1327.       }
  1328.       if (!lastItem) {
  1329.         this.log("DTA: no link found in " + links.length);
  1330.       } else if (single && w.DTA_AddingFunctions.saveSingleLink) {
  1331.         w.DTA_AddingFunctions.saveSingleLink(turbo, lastItem.url, lastItem.referrer, lastItem.description, links.postData);
  1332.       } else {
  1333.         w.DTA_AddingFunctions.saveLinkArray(turbo, anchors, images);
  1334.       }
  1335.     }
  1336.   }
  1337.   
  1338.   new FlashGotDM("FlashGet");
  1339.   
  1340.   dm = new FlashGotDM("FlashGet 2");
  1341.   dm = new FlashGotDM("FlashGet 2.x");
  1342.   dm.nativeUI = "#flashgetSingle, #flashgetAll, #flashgetSep, #flashget3Single, #flashget3All, #flashget3Sep";
  1343.   
  1344.   
  1345.   dm = new FlashGotDM("Free Download Manager");
  1346.   
  1347.   new FlashGotDM("FreshDownload");
  1348.   
  1349.   
  1350.   dm = new FlashGotDM("GetRight");
  1351.   dm.metalinkSupport = true;
  1352.   dm.download=function(links, opType) {
  1353.     if (opType == fg.OP_ONE && !fg.getPref("GetRight.quick")) {
  1354.       opType = fg.OP_SEL;
  1355.     }
  1356.     FlashGotDM.prototype.download.call(this, links, opType);
  1357.   };
  1358.   
  1359.   dm.createJob = function(links, opType) {
  1360.     var folder = links.folder;
  1361.     if (!(folder && folder._fgSelected)) folder = false;
  1362.     
  1363.     var referrer = this.getReferrer(links);
  1364.     
  1365.     switch (opType) {
  1366.       case fg.OP_ONE:
  1367.         var job = FlashGotDM.prototype.createJob.call(this, links, opType,
  1368.           fg.getPref("GetRight.old") ? ["old"] : null
  1369.           ).replace(/; /g, ";");
  1370.         return job;
  1371.       case fg.OP_SEL:
  1372.       case fg.OP_ALL:
  1373.         var urlList = "";
  1374.         var referrerLine = (referrer && referrer.length > 0) ? "\r\nReferer: " + referrer + "\r\n" : "\r\n";
  1375.         var replacer = fg.getPref("GetRight.replaceSpecialChars", true) ? /[^\w\.-]/g : /[\x00-\x1f\\]+/g;
  1376.         var l, k, len, decodedURL, urlParts, fileSpec, cookie;
  1377.         
  1378.         for (var j = 0; j < links.length; j++) {
  1379.           l=links[j];
  1380.           
  1381.           if (l.fname) fileSpec = l.fname;
  1382.           else if (folder) {
  1383.             fileSpec = '';
  1384.             decodedURL = unescape(l.href);
  1385.             urlParts = decodedURL.match(/\/\/.+[=\/]([^\/]+\.\w+)/);
  1386.             if (!urlParts) urlParts=l.href.match(/.*\/(.*\w+.*)/);
  1387.             if (urlParts && (fileSpec = urlParts[1])
  1388.               // && (links.length==1 ||  !/\.(php|[\w]?htm[l]?|asp|jsp|do|xml|rdf|\d+)$/i.test(fileSpec))
  1389.              ) {  
  1390.               urlParts = fileSpec.match(/(.*\.\w+).*/);
  1391.               if (urlParts) fileSpec = urlParts[1];
  1392.               fileSpec = fileSpec.replace(replacer, '_');
  1393.             } else continue;
  1394.           } else fileSpec = '';
  1395.           
  1396.           if (fileSpec) {
  1397.             if (folder) fileSpec = folder + "\\" + fileSpec;
  1398.             fileSpec = "File: " + fileSpec + "\r\n";
  1399.           }
  1400.           
  1401.           urlList+="URL: "+l.href
  1402.             +"\r\nDesc: "+l.description + "\r\n" + fileSpec;
  1403.           
  1404.             if (l.md5) {
  1405.             urlList += "MD5: " + l.md5 + "\r\n";
  1406.           }
  1407.           if (l.sha1) {
  1408.             urlList += "SHA1: " + l.sha1+ "\r\n";
  1409.           }
  1410.           if (l.metalinks) {
  1411.             for (k = 0, len = Math.min(16, l.metalinks.length); k < len; k++) {
  1412.               urlList += "Alt: " + l.metalinks[k] + "\r\n";
  1413.             }
  1414.           } else {
  1415.             urlList += referrerLine;
  1416.             if ((cookie = this.getCookie(l, links))) {
  1417.               urlList += "Cookie: " + cookie + "\r\n";
  1418.             }
  1419.           }
  1420.           this.updateProgress(links, j, len);
  1421.         }
  1422.         var file = fg.tmpDir.clone();
  1423.         file.append("flashgot.grx");
  1424.         file.createUnique(0,0600);
  1425.         var charset=null;
  1426.         try {
  1427.           charset=fg.getPref("GetRight.charset",
  1428.             fg.prefService.QueryInterface(CI.nsIPrefBranch
  1429.             ).getComplexValue("intl.charset.default",
  1430.               CI.nsIPrefLocalizedString).data);
  1431.         } catch(ex) {}
  1432.         IO.writeFile(file, urlList, charset);
  1433.         referrer = file.path;
  1434.         break;
  1435.     }
  1436.     var cmdOpts="/Q";
  1437.     if (fg.getPref("GetRight.autostart",false)) { // CHECK ME!!!
  1438.       cmdOpts+="\n /AUTO";
  1439.     }
  1440.     return this.createJobHeader({ length: 0, folder: "" }, opType) +
  1441.       referrer + "\n" + cmdOpts;
  1442.   };
  1443.   dm.askPath=[false,true,true];
  1444.   
  1445.   new FlashGotDM("GigaGet");
  1446.   
  1447.   new FlashGotDM("HiDownload");
  1448.   new FlashGotDM("InstantGet");
  1449.   
  1450.   dm = new FlashGotDM("iGetter Win");
  1451.   dm.nativeUI = "#all-igetter, #igetter-link";
  1452.   dm.__defineGetter__("supported", function() {
  1453.     if (typeof(this._supported) == "boolean") return this._supported;
  1454.     if (FlashGotDMMac.isMac) return this._supported = false;
  1455.     
  1456.     this._supported = ("nsIGetterMoz" in CI);
  1457.     this.cookieSupport = false;
  1458.     if (this._supported) return true;
  1459.     this.cookieSupport = true;
  1460.     return this._supported = !!this.createExecutable();
  1461.   });
  1462.   dm.createExecutable = function() {
  1463.     var exeFile, path, key;
  1464.     
  1465.     exeFile = CC["@mozilla.org/file/local;1"].createInstance(CI.nsILocalFile);
  1466.     try {
  1467.       path = this.readWinRegString("CURRENT_USER", "Software\\iGetter")
  1468.       exeFile.initWithPath(path);
  1469.     } catch(e) {
  1470.       path = null;
  1471.     }
  1472.     if (!(path && exeFile.exists())) {
  1473.       try {
  1474.         exeFile = CC["@mozilla.org/file/directory_service;1"].getService(CI.nsIProperties)
  1475.                     .get("ProgF", CI.nsIFile);
  1476.         exeFile.append("iGetter");
  1477.         exeFile.append("iGetter.exe");
  1478.       } catch(e) {
  1479.         path = "C:\\Program Files\\iGetter\\iGetter.exe";
  1480.         try {
  1481.           exeFile.initWithPath(path);
  1482.         } catch(e2) {
  1483.           return null;
  1484.         }
  1485.       }
  1486.     }
  1487.     
  1488.     this.browser = 3;
  1489.     if ("@mozilla.org/xre/app-info;1" in Components.classes) {
  1490.       var info = Components.classes["@mozilla.org/xre/app-info;1"].getService(Components.interfaces.nsIXULAppInfo);
  1491.       if(info.name.indexOf("Firefox") > -1) this.browser = 4;
  1492.     }    
  1493.     
  1494.     return exeFile.exists() ? this._exeFile = exeFile : null;
  1495.   }
  1496.   dm.createJob = function(links, opType) {
  1497.     const cs = this.cookieSupport;
  1498.     var l;
  1499.     var job = [this.getReferrer(links)];
  1500.     for (var j=0; j < links.length; j++) {
  1501.       l = links[j];
  1502.       job.push(l.href,
  1503.         cs ? l.description + "~%iget^=" + this.getCookie(l, links)
  1504.            : l.description
  1505.       );
  1506.     }
  1507.     return job.join("\r\n") + "\r\n";
  1508.   };
  1509.   dm.performJob = function(job) {
  1510.     const file = this.createJobFile(job);
  1511.     if (this.exeFile) {
  1512.       this.runNative(['-f', file.path, '-b', this.browser])
  1513.     } else {
  1514.       CC["@presenta/iGetter"]
  1515.               .getService(CI.nsIGetterMoz)
  1516.               .NewURL(file.path);
  1517.       if (file.exists()) file.remove(0);
  1518.     }
  1519.   };
  1520.   
  1521.   new FlashGotDM("Internet Download Accelerator");
  1522.   (new FlashGotDM("Internet Download Manager")).postSupport = true;
  1523.  
  1524.   var lg2002 = new FlashGotDM("LeechGet 2002");
  1525.   var lg2004 = new FlashGotDM("LeechGet");
  1526.   
  1527.   lg2004.createJob = lg2002.createJob = function(links, opType) {
  1528.     var referrer;
  1529.     switch (opType) {
  1530.       case fg.OP_ONE:
  1531.         return FlashGotDM.prototype.createJob.call(this, links, 
  1532.             links.quickDownload ? fg.OP_ONE : fg.OP_SEL);
  1533.         
  1534.       case fg.OP_SEL:
  1535.         var htmlDoc="<html><head><title>FlashGot selection</title></head><body>";
  1536.         var l;
  1537.         for (var j=0, len=links.length; j<len; j++) {
  1538.           l = links[j];
  1539.           var des = l.description;
  1540.           var tag = l.tagName ? l.tagName.toLowerCase() : "";
  1541.           htmlDoc = htmlDoc.concat(tag == "img"
  1542.             ? '<img src="' + l.href + '" alt="' + des
  1543.               + '" width="' + l.width + '" height="' + l.height +
  1544.               "\" />\n"
  1545.             : "<a href=\"" + l.href + "\">" + des + "</a>\n");
  1546.           this.updateProgress(links, j, len);
  1547.         }
  1548.         referrer = fg.httpServer.addDoc(
  1549.           htmlDoc.concat("</body></html>")
  1550.         );
  1551.         break;
  1552.        default:
  1553.         referrer = links.document && links.document.URL || "";
  1554.         if (referrer.match(/^\s*file:/i)) { // fix for local URLs
  1555.           // we serve local URLs through built-in HTTP server...
  1556.           return this.createJob(links,fg.OP_SEL);
  1557.         }
  1558.     }
  1559.     return this.createJobHeader({ length: 0, folder: "" },opType) + referrer + "\n";
  1560.   };
  1561.  
  1562.   new FlashGotDM("Net Transport");
  1563.   new FlashGotDM("Net Transport 2");
  1564.   new FlashGotDM("NetAnts");
  1565.   new FlashGotDM("Mass Downloader");
  1566.   
  1567.   dm = new FlashGotDM("Orbit");
  1568.   dm.nativeUI = "#OrbitDownloadUp, #OrbitDownload, #OrbitDownloadAll, #OrbidDownload_menuitem, #OrbitDownloadAll_menuitem";
  1569.   
  1570.   dm = new FlashGotDM("ReGet");
  1571.   dm.postSupport = true;
  1572.   if("@reget.com/regetextension;1" in CC) {
  1573.     try {
  1574.       dm.reGetService = CC["@reget.com/regetextension;1"].createInstance(CI.IRegetDownloadFFExtension);
  1575.       if (dm.reGetService.isExtensionEnabled()) {
  1576.         dm._supported = true;
  1577.         dm.performJob = function() {};
  1578.         dm.createJob = function(links, opType) {
  1579.           const rg = this.reGetService;
  1580.           var l;
  1581.           var len = links.length;
  1582.           var ref = links.referrer;
  1583.           if (len == 1) {
  1584.             l = links[0];
  1585.             rg.setUrl(l.href);
  1586.             rg.setInfo(l.description);
  1587.             rg.setCookie(this.getCookie(l, links));
  1588.             rg.setReferer(ref);
  1589.             rg.setPostData(links.postData);
  1590.             rg.setConfirmation(true);
  1591.             rg.addDownload();
  1592.             return;
  1593.           }
  1594.           for (var j = 0; j < len; j++) {
  1595.             l = links[j];
  1596.             rg.addToMassDownloadList(
  1597.               l.href,
  1598.               ref,
  1599.               this.getCookie(l, links),
  1600.               l.description,
  1601.               "");
  1602.             this.updateProgress(links, j, len);
  1603.           }
  1604.           rg.runMassDownloadList();
  1605.         }
  1606.       }
  1607.     } catch(rgEx) {}
  1608.   }
  1609.   
  1610.   if (isWin) {
  1611.     dm = new FlashGotDMCust("Retriever");
  1612.     dm.cookieSupport = true;
  1613.     dm.askPath = ASK_NEVER;
  1614.     dm.custom = false;
  1615.     dm._supported = null;
  1616.     
  1617.     if (fg.getPref(dm.prefsBase + "maxLinks", -1000) == -1000) {
  1618.       fg.setPref(dm.prefsBase + "maxLinks", 10);
  1619.     }
  1620.     dm.customSupportCheck = function() {
  1621.       try {
  1622.         var cmd = this.readWinRegString("CLASSES_ROOT", "Retriever.Retriever.jar.HalogenWare\\shell\\Open\\command");
  1623.         this.jarPath = cmd.replace(/.*-jar "?(.*?\.jar).*/, "$1");
  1624.         this.argsTemplate = "[URL] [Referer:REFERER] [Cookie:COOKIE] [post:POST]";
  1625.         
  1626.         var exeFile = CC["@mozilla.org/file/directory_service;1"].getService(CI.nsIProperties)
  1627.           .get("WinD", CI.nsIFile);
  1628.         exeFile.append("System32");
  1629.         exeFile.append("javaw.exe");
  1630.         this.exeFile = exeFile;
  1631.         
  1632.         return true;
  1633.       } catch(e) {
  1634.         return false;
  1635.       } 
  1636.     };
  1637.     
  1638.     dm.makeArgs = function(parms) {
  1639.       return ["-jar", this.jarPath].concat(
  1640.         FlashGotDMCust.prototype.makeArgs.apply(this, arguments)
  1641.       );
  1642.     };
  1643.     
  1644.     dm = new FlashGotDMCust("DownloadStudio");
  1645.     dm.cookieSupport = true;
  1646.     dm.askPath = ASK_NEVER;
  1647.     dm.custom = false;
  1648.     dm._supported = null;
  1649.     
  1650.     dm.customSupportCheck = function() {
  1651.       try {
  1652.         var path = this.readWinRegString("LOCAL_MACHINE", "SOFTWARE\\Conceiva\\DownloadStudio", "Path");
  1653.         if (!path) return false;
  1654.         var exeFile = CC["@mozilla.org/file/local;1"].createInstance(CI.nsILocalFile);
  1655.         exeFile.initWithPath(path);
  1656.         exeFile.append("DownloadStudio.exe");
  1657.         if (exeFile.exists() && exeFile.isExecutable()){
  1658.           this.exeFile = exeFile;
  1659.           this.argsTemplate = "<downloadstudio><originator>firefox</originator> " +
  1660.             "<script><add_jobs display_dialog=yes><joblist><job> [<url>URL</url>] " +
  1661.             "[<url_list_file>UFILE</url_list_file>] [<referer>REFERER</referer>] " +
  1662.             "[<post_data>POST</post_data>] [<cookie>COOKIE</cookie>] " +
  1663.             "</job></joblist></add_jobs></script></downloadstudio>";
  1664.           return true;
  1665.         }
  1666.       } catch(e) {}
  1667.       return false;
  1668.     };
  1669.     
  1670.   }
  1671.   
  1672.   const httpFtpValidator = function(url) {
  1673.     return /^(http:|ftp:)/.test(url);
  1674.   };
  1675.   dm = new FlashGotDM("Star Downloader");
  1676.   dm.cookieSupport = false;
  1677.   dm.isValidLink = httpFtpValidator;
  1678.   
  1679.   dm = new FlashGotDM("TrueDownloader");
  1680.   dm.isValidLink = httpFtpValidator;
  1681.   
  1682.  
  1683.   dm = new FlashGotDM("Thunder");
  1684.   dm.nativeUI = "#ThunderDownloadUp, #ThunderDownload, #ThunderDownloadAll";
  1685.   dm.thunderDelay = 3000;
  1686.   dm.performDownload = function(links, opType) {
  1687.     var self = this;
  1688.     var postCall = function() {
  1689.       self.__proto__.performDownload.call(self, links, opType);
  1690.     }
  1691.     try {
  1692.       var path = this.readWinRegString("LOCAL_MACHINE","Software\\Thunder Network\\ThunderOem\\thunder_backwnd", "Path");
  1693.       var exeFile = CC["@mozilla.org/file/local;1"].createInstance(CI.nsILocalFile);
  1694.       exeFile.initWithPath(path);
  1695.       this.runNative([], false, exeFile);
  1696.       fg.delayExec(postCall, this.thunderDelay); // give thunder one second to popup (more if cold start)
  1697.       this.thunderDelay = 1000;
  1698.       return;
  1699.     } catch(e) {}
  1700.     postCall;
  1701.   }
  1702.   new FlashGotDM("Thunder (Old)");
  1703.  
  1704.   
  1705.   if (isWin) {
  1706.     dm = new FlashGotDM("WellGet");
  1707.     dm.autoselect = false;
  1708.     dm.getRelativeExe = function() {
  1709.       try {
  1710.         return fg.prefs.getComplexValue("WellGet.path", CI.nsILocalFile);
  1711.       } catch(ex) {}
  1712.       return null;
  1713.     };
  1714.     dm.customSupportCheck = function() {
  1715.       var wellGetExe = this.getRelativeExe();
  1716.       try {
  1717.          var currentPath = wellGetExe.path;
  1718.          if(wellGetExe.exists() && wellGetExe.isExecutable()) return true;
  1719.          
  1720.          wellGetExe.initWithPath(fg.profDir.path.substring(0,2) +
  1721.            currentPath.substring(2));
  1722.          if (wellGetExe.exists() && wellGetExe.isExecutable()) {
  1723.            if(wellGetExe.path != currentPath) {
  1724.               fg.prefs.setComplexValue("WellGet.path",  CI.nsILocalFile, wellGetExe);
  1725.            }
  1726.            return true;
  1727.          }
  1728.          return false;
  1729.       } catch(ex) {
  1730.       }
  1731.       
  1732.       return !wellGetExe && this.baseSupportCheck();
  1733.     };
  1734.     dm.createJob = function(links, opType) {
  1735.       var wellGetExe = this.getRelativeExe();
  1736.       return FlashGotDM.prototype.createJob.call(this, links, opType, 
  1737.         wellGetExe ? [wellGetExe.path] : null);
  1738.     };
  1739.     dm.shouldList = function() { return true; }
  1740.   }
  1741.  
  1742.   dm = new FlashGotDM("JDownloader");
  1743.   dm.askPath = [true, true, true];
  1744.   dm.cookieSupport = true;
  1745.   dm.customSupportCheck = function() {
  1746.     try {
  1747.       if (this._checkPath()) return true;
  1748.       
  1749.       var self = this;
  1750.       fg.delayExec(function() {
  1751.         var r = self._createRequest("GET", function(r) {
  1752.           self._handleResponse(r.responseText.split(/[\r\n]+/));
  1753.         });
  1754.         r.send(null);
  1755.       }, 0);
  1756.     } catch(e) {
  1757.       fg.log(e);
  1758.     }
  1759.     return false;
  1760.   };
  1761.   dm._handleResponse = function(res) {
  1762.     if (res.length < 2) return;
  1763.     var p = res[0];
  1764.     if (fg.isWindows) p = p.replace(/\//g, '\\');
  1765.     this.setPref("path", p);
  1766.     if (this._checkPath()) {
  1767.       this.setPref("args", res[1].substring(0, res[1].lastIndexOf(res[0])).replace(/^java\s*/, ''));
  1768.       this._supported = true;
  1769.     }
  1770.   };
  1771.   dm._checkPath = function() {
  1772.     try {
  1773.     var p = this.getPref("path", "");
  1774.       if (p) {
  1775.         var f = CC["@mozilla.org/file/local;1"].createInstance(CI.nsILocalFile);
  1776.         f.initWithPath(p);
  1777.         if (f.exists()) {
  1778.           this.jdFile = f;
  1779.           return true;
  1780.         }
  1781.       }
  1782.     } catch(e) {}
  1783.     this.setPref("path", "");
  1784.     this.jdFile = null;
  1785.     return false;
  1786.   };
  1787.   
  1788.   dm._winExe = function() {
  1789.     var exe = null;
  1790.     if (fg.isWindows) try {
  1791.       var fname = this.jdFile.leafName;
  1792.       if (/\.(jar|exe)$/.test(fname)) {
  1793.         var f = this.jdFile.clone();
  1794.         f.leafName = fname.replace(/jar$/, 'exe');
  1795.         if (f.exists() && f.isExecutable()) this.jdFile = exe = f;
  1796.       }
  1797.     } catch (e) {}
  1798.     return exe;
  1799.   };
  1800.   
  1801.   dm._macExe = function() {
  1802.     try {
  1803.       if (!/\.app\/Contents\/Resources\/Java\/[^\/]+\.jar$/.test(this.jdFile.path)) return null;
  1804.       var exe = this.jdFile.parent.parent.parent;
  1805.       exe.append("MacOS");
  1806.       exe.append("JavaApplicationStub");
  1807.       return exe.exists() ? exe : null;
  1808.     } catch (e) {
  1809.       return null;
  1810.     }
  1811.   },
  1812.   
  1813.   dm._createRequest = function(method, callback) {
  1814.     var r = CC["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(CI.nsIXMLHttpRequest);
  1815.     var url = this.getPref("url");
  1816.     r.open(method, url, true);
  1817.     try {
  1818.       var chan = r.channel;
  1819.       if (chan instanceof CI.nsIHttpChannel) {
  1820.         var referrer = chan.URI.clone();
  1821.         referrer.host = "localhost";
  1822.         chan.referrer = referrer;
  1823.       }
  1824.     } catch(e) {
  1825.       fg.log(e);
  1826.     }
  1827.     
  1828.     if (callback) {
  1829.       r.onreadystatechange = function() {
  1830.         if (r.readyState == 4) {
  1831.           try {
  1832.             fg.log("JDownloader response:\n" + r.status + "\n" + r.responseText);
  1833.           } catch (e) {}
  1834.           callback(r);
  1835.         }
  1836.       };
  1837.     }
  1838.     return r;
  1839.   }
  1840.   dm.MAX_RETRIES = 6;
  1841.   dm.performDownload = function(links, opType) {
  1842.     var pp = { urls: [], descriptions: [], cookies: [] };
  1843.     var l, j, len;
  1844.     for (j = 0, len = links.length; j < len; j++) {
  1845.       l = links[j];
  1846.       pp.urls.push(l.href);
  1847.       pp.descriptions.push(l.description);
  1848.       pp.cookies.push(this.getCookie(l, links));
  1849.     }
  1850.  
  1851.     var data = [
  1852.       "referer=" + encodeURIComponent(this.getReferrer(links)),
  1853.       "autostart=" + (this.getPref("autostart", true) ? "1" : "0"),
  1854.       "package=" + encodeURIComponent(links.document && links.document.title || "FlashGot")
  1855.     ];
  1856.     if (links.folder && links.folder._fgSelected) data.push("dir=" + encodeURIComponent(links.folder));              
  1857.     if (links.postData) data.push("postData=" + encodeURIComponent(links.postData));
  1858.     for (j in pp) {
  1859.       data.push(j + "=" + encodeURIComponent(pp[j].join("\n")));
  1860.     }
  1861.     this._post(data.join("&"), this.MAX_RETRIES);
  1862.   };
  1863.   dm._post = function(data, retries) {
  1864.     var self = this;
  1865.     var r = this._createRequest("POST", function(r) {
  1866.       if (r.status != 200) self._handleRetry(data, retries);
  1867.     });
  1868.     
  1869.     r.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  1870.     r.send(data);
  1871.   };
  1872.   
  1873.   dm._handleRetry = function(data, retries) {
  1874.     var msg, fail = true;
  1875.     if (retries-- == this.MAX_RETRIES) {
  1876.       try {
  1877.         var args,
  1878.             exe = this._winExe() || this._macExe();
  1879.         if (exe) {
  1880.           args = [];
  1881.         } else {
  1882.           if (!this.java) {
  1883.             var java = CC["@mozilla.org/file/local;1"].createInstance(CI.nsILocalFile);
  1884.             try {
  1885.               java.initWithPath(DOM.mostRecentBrowserWindow.java.lang.System.getProperty("java.home"));
  1886.               java.append("bin");
  1887.               java.append(fg.isWindows ? "javaw.exe" : "java");
  1888.             } catch (e) {
  1889.               java.initWithPath("/usr/bin/java");
  1890.             }
  1891.             this.java = java;
  1892.           }
  1893.           exe = this.java;
  1894.           args = this.getPref("args", '').split(/\s+/);
  1895.           args.push(this.jdFile.path);
  1896.         }
  1897.         fail = !this.runNative(args, false, exe);
  1898.       } catch(e) {
  1899.         fg.log(e);
  1900.         this.java = null;
  1901.       } 
  1902.       if (fail) msg = "Cannot launch " + (this.jdFile && this.jdFile.path || "JDownloader") + ". Please launch it manually or ensure Java is enabled in your browser.";
  1903.     } else if (retries == 0) {
  1904.       msg = "JDownloader not responding on " + this.getPref("url") + "!\nPlease check your firewall settings.";
  1905.     } else {
  1906.       fail = false;
  1907.     }
  1908.     if (fail) {
  1909.       DOM.mostRecentBrowserWindow.alert(msg);
  1910.     } else {
  1911.       var self = this;
  1912.       fg.delayExec(function() { self._post(data, retries); }, this.getPref("delay", 8) * 1000);
  1913.     }
  1914.   };
  1915.  
  1916.   dm = new FlashGotDMX("Aria", "aria", "[-r REFERER] [-d FOLDER] -g [URL]");
  1917.   dm.createJob = function(links,opType) {
  1918.     return FlashGotDMX.prototype.createJob.call(this,links,opType) + "\nsleep 4\n" + this.unixCmd + " -s &\n";
  1919.   };
  1920.   
  1921.   dm = new FlashGotDMX("Downloader 4 X (nt)", "nt");
  1922.   dm.createJob = function(links,opType) {
  1923.     return this.unixCmd + "&\nsleep 1\n" +
  1924.       (links.folder && links.folder._fgSelected
  1925.       ? this.unixCmd + " -d " + this.shellEsc(links.folder) + "\n"
  1926.       :"") + 
  1927.       FlashGotDMX.prototype.createJob.call(this,links,opType);
  1928.   };
  1929.   
  1930.   dm = new FlashGotDMX("Downloader 4 X", "d4x", "[--referer REFERER] [-a URL] [--al POST] [COOKIE]");
  1931.   dm.askPath = [false, true, true];
  1932.   dm.cookieSupport = true;
  1933.   dm.createJob = function(links, opType) {
  1934.     const shellEsc = this.shellEsc;
  1935.     const referrer = shellEsc(this.getReferrer(links));
  1936.     const folder = links.folder._fgSelected && links.folder || null;
  1937.     const quiet = this.quiet;
  1938.     const len = links.length;
  1939.     var job;
  1940.     
  1941.     if (len > 0) {
  1942.         
  1943.       var urls = [];
  1944.       for (var j = 0; j < len; j++) {
  1945.         urls.push(shellEsc(links[j].href));
  1946.         this.updateProgress(links, j, len);
  1947.       }
  1948.       urls = urls.join(" ");
  1949.       
  1950.       var promptURLs_fakePost = null;
  1951.       var quietURLs_fakeCookie = null;
  1952.       
  1953.       if (quiet) {
  1954.         quietURLs_fakeCookie = urls;
  1955.         urls = null;
  1956.       } else if(len > 1) {
  1957.         promptURLs_fakePost = urls;
  1958.         urls = null;
  1959.       }
  1960.       
  1961.       var cookieFile = this.createCookieFile();
  1962.       
  1963.       job = (cookieFile && cookieFile.path)
  1964.         ? "mkdir -p $HOME/.netscape && ln -fs " + 
  1965.           shellEsc(cookieFile.path) + 
  1966.           " $HOME/.netscape/cookies\n"
  1967.         : "";
  1968.       
  1969.       if (folder) job += this.unixCmd + " -d " + shellEsc(folder) + "\n";
  1970.       
  1971.       job += this.createCmdLine({
  1972.          URL: urls, 
  1973.          REFERER: referrer,
  1974.          COOKIE: quietURLs_fakeCookie || null,
  1975.          POST: promptURLs_fakePost
  1976.       }); 
  1977.     } else job = "";
  1978.     
  1979.     return job;
  1980.   };
  1981.   
  1982.   dm = new FlashGotDMX("GNOME Gwget","gwget");
  1983.   dm.askPath = ASK_NEVER;
  1984.   dm.createJob = function(links, opType) {
  1985.     if (opType == fg.OP_ALL) {
  1986.       links.length = 1;
  1987.       links[0].href = links.document ? links.document.URL : this.getReferrer(links);
  1988.       opType = fg.OP_ONE;
  1989.     }
  1990.     return FlashGotDMX.prototype.createJob.call(this, links, opType)
  1991.   } 
  1992.   
  1993.   dm = new FlashGotDMX("KDE KGet","kget");
  1994.   dm.askPath = ASK_NEVER;
  1995.   
  1996.   if (isWin) {
  1997.     new FlashGotDM("wxDownload Fast");
  1998.   } else {
  1999.     dm = new FlashGotDMX("wxDownload Fast", "wxdfast", "[-reference REFERER] [-destination FOLDER] [-list UFILE]");
  2000.     dm.askPath = ASK_NEVER;
  2001.   }
  2002.   
  2003.   dm = new FlashGotDMX("Axel","axel", '-n 4 [URL]');
  2004.   dm.terminal = true;
  2005.   dm.createJob = function(links, opType) {
  2006.     this.argsTemplate = this.argsTemplate.replace(/^-n \d+/, "-n " + this.getPref("connections", 4));  
  2007.     return this.__proto__.createJob.call(this, links , opType);
  2008.   };
  2009.   
  2010.   dm = new FlashGotDMX("cURL","curl", '-L -O [-o FNAME] [--referer REFERER] [-b COOKIE] [-d POST] [URL]');
  2011.   dm.postSupport = true;
  2012.   dm.terminal = true;
  2013.   if (FlashGotDMMac.isMac) dm.autoselect = false;
  2014.   
  2015.   dm = new FlashGotDMX("Wget", "wget", '-c [-O FNAME] [--directory-prefix=FOLDER] [--referer=REFERER] [--post-data=POST] [--load-cookies=CFILE] [--header=Cookie:COOKIE] [--input-file=UFILE]');
  2016.   dm.postSupport = true;
  2017.   dm.terminal = true;
  2018.   
  2019.   if (fg.isWindows) {
  2020.     dm = new FlashGotDMCust("Uget");
  2021.     dm.cookieSupport = true;
  2022.     dm.askPath = ASK_NEVER;
  2023.     dm.custom = false;
  2024.     dm._supported = null;
  2025.     
  2026.     dm.customSupportCheck = function() {
  2027.       var path;
  2028.       try {
  2029.         path = this.readWinRegString("LOCAL_MACHINE", "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\uget.exe");
  2030.       } catch (e) {
  2031.         path = this.getPref("path");
  2032.       }
  2033.         
  2034.       if (!path) return false;
  2035.       
  2036.       try {  
  2037.         var exeFile = CC["@mozilla.org/file/local;1"].createInstance(CI.nsILocalFile);
  2038.         exeFile.initWithPath(path);
  2039.         if (!(exeFile.exists() && exeFile.isExecutable())) return false;
  2040.         this.exeFile = exeFile;
  2041.         return true;
  2042.       } catch(e) {
  2043.         return false;
  2044.       } 
  2045.     };
  2046.     
  2047.     
  2048.   } else {
  2049.     dm = new FlashGotDMX("Uget", "uget-gtk", '');
  2050.     dm.postSupport = true;
  2051.     dm.askPath = ASK_NEVER;
  2052.   }
  2053.   
  2054.   dm.performDownload = function(links, opType) {
  2055.     this.argsTemplate = '[--http-cookie-file=CFILE] [--http-post-data=POST] [--http-referer=REFERER] ' +
  2056.      ((opType == fg.OP_ONE) ? '[URL]' : '[--input-file=UFILE]'); 
  2057.     this.__proto__.performDownload.apply(this, arguments);
  2058.   }
  2059.   
  2060.   
  2061.   dm = new FlashGotDMX("Aria 2", "aria2c", '--continue [-d FOLDER] [-o FNAME] [--referer=REFERER] [--load-cookies=CFILE] [--input-file=UFILE]');
  2062.   dm.postSupport = false;
  2063.   dm.terminal = true;
  2064.   
  2065.   if (FlashGotDMMac.isMac) {
  2066.     dm = new FlashGotDMX("PSD", "$(defaults read com.PS.PSD psAppPath)", "-add [url UFILE] [cookie CFILE] [referer REFERER] [destination FOLDER]");
  2067.     dm.postSupport = false;
  2068.   }
  2069.   
  2070.   function FlashGotDMSD(version) {
  2071.     this._initMac(typeof(version) == "number" && version > 3 ? "Speed Download" : ("Speed Download " + version), "Spee");
  2072.     this.version = version;
  2073.     if (version > 2 || version == "Lite") {
  2074.       this.cookieSupport = true;
  2075.       this.postSupport = true;
  2076.     }
  2077.   };
  2078.   
  2079.   FlashGotDMSD.prototype=new FlashGotDMMac();
  2080.   FlashGotDMSD.prototype.createJob = function(links,opType) {
  2081.     var urlList = [];
  2082.     var cookieList = [];
  2083.     var l;
  2084.     for (var j=0, len = links.length; j < len; j++) {
  2085.       l = links[j];
  2086.       urlList.push(l.href);
  2087.       if (this.cookieSupport) {
  2088.         cookieList.push(this.getCookie(l, links));
  2089.       }
  2090.       this.updateProgress(links, j, len);
  2091.     }
  2092.     var job = 'tell app "' + this.macAppName + 
  2093.       '" to AddURL {"' + urlList.join('","') + '"}';
  2094.     
  2095.     if (this.postSupport) {
  2096.  
  2097.       if (links.postData) { 
  2098.         job +=' with form data "' + links.postData + '"';
  2099.       }
  2100.  
  2101.       const referer = this.getReferrer(links);
  2102.       if (referer && referer.length) {
  2103.         job += ' from "' + referer + '"';
  2104.       }
  2105.  
  2106.       if (cookieList.length) {
  2107.         job += ' with cookies {"' + cookieList.join('","') + '"}';
  2108.       }
  2109.     }
  2110.     
  2111.     return job;
  2112.   };
  2113.   
  2114.   if (fg.getPref("oldSD", false)) {
  2115.     new FlashGotDMSD(2);
  2116.     new FlashGotDMSD(3);
  2117.   }
  2118.   new FlashGotDMSD(3.5);
  2119.   new FlashGotDMSD("Lite");
  2120.   
  2121.   dm = new FlashGotDMMac("Leech", "com.manytricks.Leech");
  2122.   dm.askPath = [true, true, true];
  2123.   dm.cookieSupport = dm.postSupport = true;
  2124.   dm.createJob = function(links, opType) {
  2125.     var urlList = [];
  2126.     var cookieList = [];
  2127.     var l;
  2128.     for (var j = 0, len = links.length; j < len; j++) {
  2129.       l = links[j];
  2130.       urlList.push(l.href);
  2131.       if (this.cookieSupport) {
  2132.         cookieList.push(this.getCookie(l, links).replace(/;\s*$/, ''));
  2133.       }
  2134.       this.updateProgress(links, j, len);
  2135.     }
  2136.     
  2137.     var job = 'tell app "' + this.macAppName + '" to download URLs {"'
  2138.       + urlList.join('", "') + '"}';
  2139.     if (links.postData) {
  2140.       job += ' by posting data "' + links.postData + '"';
  2141.     }
  2142.     job += ' to POSIX path "' + links.folder + '"';
  2143.     if (cookieList.length) {
  2144.       job += ' using cookies "' + cookieList.join('; ') + '; "'; 
  2145.     }
  2146.     const referer = this.getReferrer(links);
  2147.     if (referer && referer.length) {
  2148.       job += ' with referrer "' + referer + '"';
  2149.     }
  2150.     
  2151.     return job;
  2152.   }
  2153.   
  2154.   dm = new FlashGotDMMac("iGetter", "iGET");
  2155.   dm.cookieSupport = true;
  2156.   dm.createJob = function(links, opType) {
  2157.     const referrer = this.getReferrer(links);
  2158.     var l, params = [];
  2159.     for (var j = 0, len = links.length; j < len; j++) {
  2160.       l = links[j];
  2161.       params.push('{\u00ABclass ----\u00BB:"' + l.href + 
  2162.         '", \u00ABclass refe\u00BB:"' + referrer  + 
  2163.         '", \u00ABclass cook\u00BB:"' + this.getCookie(l, links) +
  2164.         '"}');
  2165.       this.updateProgress(links, j, len);
  2166.     }
  2167.     return "tell application \"" + this.macAppName + 
  2168.       "\"\n\u00ABevent iGETGURL\u00BB {" +
  2169.        params.join(",") +
  2170.       "} given \u00ABclass brsg\u00BB:\"MOZB\"\n" +
  2171.       "end tell\n";
  2172.   };
  2173.   
  2174.   dm = new FlashGotDMMac("Folx", "com.eltima.Folx")
  2175.   dm.cookieSupport = true;
  2176.   dm.createJob = function(links, opType) {
  2177.     var urls = [], cookies = [], titles = [];
  2178.     for (var j = 0, len = links.length, l; j < len; j++) {
  2179.       l = links[j];
  2180.       urls.push(l.href);
  2181.       cookies.push(this.getCookie(l, links));
  2182.       titles.push(l.description.replace(/[\u0000-\u0020"\s]+/g, ' '));
  2183.     }
  2184.     var job = "tell application \""+ this.macAppName + "\"\n" +
  2185.       'add URLs {"' + urls.join('", "') + 
  2186.       "\"} with referrer \"" + this.getReferrer(links) +
  2187.       "\" with cookies {\"" + cookies.join('", "') +
  2188.       "\"} with titles {\"" + titles.join('", "') +
  2189.       "\"} ";
  2190.     if (links.postData)
  2191.       job += 'with post data "' + links.postData + '"';
  2192.     return job + " from applecation \"FlashGot\"\nend tell\n";
  2193.   }
  2194.   
  2195.   if ("nsIDownloadManager" in CI) {
  2196.     dm = new FlashGotDM(fg.getString("dm.builtIn"));
  2197.     dm._codeName = "_Built_In_";
  2198.     dm._supported = true;
  2199.     dm.priority = "zzz"; // put on the bottom of the list
  2200.     
  2201.     dm.askPath = [true, true, true];
  2202.     dm.postSupport = true;
  2203.     
  2204.     dm._checkLinks = function(links, cs, callback) {
  2205.       var l, ch,
  2206.         count = links.length,
  2207.         noRedir = this.getPref("noRedir") || links.postData,
  2208.         allDone = true,
  2209.         progressHolder = { progress: links.progress };
  2210.       
  2211.       var rx;
  2212.       try {
  2213.         rx = new RegExp(this.getPref("noRedir.extensions"), "i");
  2214.       } catch (e) {}
  2215.       
  2216.       for (var j = links.length; j-- > 0;) {
  2217.         l = links[j];
  2218.         l.uri = IOS.newURI(l.href, cs, null);
  2219.         
  2220.         if (noRedir || l.fname || !(l.uri instanceof CI.nsIURL) ||
  2221.             rx && rx.test(l.uri.fileName)) {
  2222.           count--;
  2223.           continue;
  2224.         }
  2225.         
  2226.         allDone = false;
  2227.         
  2228.         ch = IOS.newChannelFromURI(l.uri);
  2229.         ch.asyncOpen({
  2230.           dm: this,
  2231.           link: l,
  2232.           onStartRequest: function(ch, ctx) {
  2233.             if (!(ch instanceof CI.nsIHttpChannel) || Math.round(ch.responseStatus / 100) != 3)
  2234.               this._done(ch);
  2235.           },
  2236.           onDataAvailable: function(req, ctx , stream , offset , count ) {
  2237.             this._done(ch);
  2238.           },
  2239.           onStopRequest: function(req, ctx, status) {
  2240.           },
  2241.  
  2242.           _done: function(ch) {
  2243.             ch.cancel(NS_BINDING_ABORTED);
  2244.             if (ch instanceof CI.nsIHttpChannel && ch.responseStatus == 200 && !/\b(?:x|ht)ml\b/.test(ch.contentType)) {
  2245.               this.link.uri = ch.URI;
  2246.               try {
  2247.                 this.link.fname = ch.getResponseHeader("content-disposition").match(/; filename="([^"]+)/i)[1];
  2248.               } catch(e) {}
  2249.             }
  2250.             
  2251.             if (--count === 0) {
  2252.               callback();
  2253.               progressHolder.progress.update(100);
  2254.             } else {
  2255.               this.dm.updateProgress(progressHolder, links.length - count, links.length);
  2256.             }
  2257.           }
  2258.         }, null);
  2259.       }
  2260.       
  2261.       if (allDone) callback();
  2262.       else links.progress = null; // prevents the progress bar from being filled immediately
  2263.     };
  2264.     
  2265.     dm._prepareDownload = function(links, opType) {
  2266.       const cs = links.document && links.document.characterSet || "UTF-8";
  2267.       var ref = this.getReferrer(links);
  2268.       links.refURI = ref && IOS.newURI(ref, cs, null) || null;
  2269.       var self = this;
  2270.       this._checkLinks(links, cs, function() { self.performDownload(links, opType); });
  2271.     };
  2272.     
  2273.     dm.performDownload = function(links, opType) {
  2274.       if (!links._prepared) {
  2275.         links._prepared = true;
  2276.         this._prepareDownload(links, opType);
  2277.         return;
  2278.       }
  2279.       
  2280.       const persistFlags = CI.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
  2281.         CI.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION |
  2282.         CI.nsIWebBrowserPersist.PERSIST_FLAGS_FROM_CACHE;
  2283.       
  2284.       const dType = CI.nsIDownloadManager.DOWNLOAD_TYPE_DOWNLOAD;
  2285.       var postData = links.postStream || null;
  2286.  
  2287.       var uri, folder, file;
  2288.       var persist, args;
  2289.       var now = Date.now() * 1000;
  2290.       var dm = CC["@mozilla.org/download-manager;1"].getService(CI.nsIDownloadManager);
  2291.       folder = CC["@mozilla.org/file/local;1"].createInstance(CI.nsILocalFile);
  2292.       folder.initWithPath(links.folder);
  2293.       var mozAddDownload;
  2294.       if(dm.startBatchUpdate) {
  2295.         mozAddDownload = typeof(dType) == "undefined" 
  2296.           ? function(src, dest, des, persist) { return dm.addDownload(src, dest, des, null, now, null, persist); }
  2297.           : function(src, dest, des, persist) { return dm.addDownload(dType, src, dest, des, null, null, now, null, persist); }
  2298.           ;
  2299.         dm.startBatchUpdate();
  2300.       } else {
  2301.         mozAddDownload = function(src, dest, des, persist) { return dm.addDownload(dType, src, dest, des, null, now, null, persist); };
  2302.       }
  2303.       var dl;
  2304.       const overwrite = this.getPref("overwrite", false);
  2305.       for(var j = 0, len = links.length, l; j < len; j++) {
  2306.         l = links[j];
  2307.         try {
  2308.           uri = l.uri;
  2309.           
  2310.           file = fg.createDownloadFile(folder, l.fname || uri, overwrite);
  2311.           
  2312.           if (!file) continue;
  2313.           
  2314.           persist = CC["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(CI.nsIWebBrowserPersist);
  2315.           persist.persistFlags = persistFlags;
  2316.           
  2317.           fg.log("Saving " + l.href + " to " + file.path);
  2318.           
  2319.           persist.progressListener = dl = 
  2320.             mozAddDownload(uri, IOS.newFileURI(file), file.leafName, persist)
  2321.               .QueryInterface(CI.nsIWebProgressListener);
  2322.           const cacheKey  = CC['@mozilla.org/supports-string;1'].createInstance(CI.nsISupportsString);
  2323.           cacheKey.data = uri.spec;
  2324.           persist.saveURI(uri, cacheKey,
  2325.                   links.refURI, postData, null, file);
  2326.         } catch (e) {
  2327.           fg.log("Skipping link " + l.href + ": " + e);
  2328.         }
  2329.       }
  2330.       if(dm.endBatchUpdate) dm.endBatchUpdate();
  2331.       if(dm.flush) dm.flush();
  2332.       
  2333.       if(this.getPref("showDM", true)) {
  2334.         try { // SeaMonkey
  2335.           dm.open(links.browserWindow, dl);
  2336.         } catch(notSeamonkey) {
  2337.           
  2338.           const DMBRANCH = "browser.download.manager.";
  2339.           var prefs = fg.prefService.getBranch(DMBRANCH);
  2340.           try {
  2341.             if (!(prefs.getBoolPref("showWhenStarting") && prefs.getBoolPref("useWindow")))
  2342.               return;
  2343.           } catch(noPref) {
  2344.             return;
  2345.           }
  2346.  
  2347.           try { // 1.9 (Toolkit)
  2348.              // http://mxr.mozilla.org/seamonkey/source/toolkit/components/downloads/src/nsDownloadProxy.h#94
  2349.              var dmui = CC["@mozilla.org/download-manager-ui;1"].getService(CI.nsIDownloadManagerUI);
  2350.              var focus = false;
  2351.              try {
  2352.                focus = prefs.getBoolPref("focusWhenStarting");
  2353.              } catch(noPref) {}
  2354.              if (dmui.visible && !focus) {
  2355.                dmui.getAttention();
  2356.                return;
  2357.              }
  2358.              dmui.show(null, dl, CI.nsIDownloadManagerUI.REASON_NEW_DOWNLOAD);
  2359.           } catch(e1) {
  2360.             try { // 1.8 (Firefox 2)
  2361.               links.browserWindow.document.getElementById("Tools:Downloads").doCommand();
  2362.             } catch(e2) {
  2363.             }
  2364.           }
  2365.         }
  2366.       }
  2367.     };
  2368.   }
  2369.   
  2370.   FlashGotDMCust.init();
  2371.   
  2372.   fg.sortDMS();
  2373.   
  2374.   dm = null;
  2375. };